package jiuwu.gqz.audiorecord

import android.media.*
import android.os.Environment
import android.util.Log
import java.io.FileInputStream
import java.nio.ByteBuffer
import java.util.*

class AudioPlayDecoder : Thread() {

    val TAG = "AudioPlayDecoder-->"

    val sampleRate = 16000
    val channelCount = 1
    val mime = MediaFormat.MIMETYPE_AUDIO_AAC
    val audioFormat = AudioFormat.ENCODING_PCM_16BIT
    val minAACFrameSize = 50

    //init audioTrack
    val streamType = AudioManager.STREAM_MUSIC
    val sampleRateInHz = sampleRate
    val channelConfig = AudioFormat.CHANNEL_OUT_MONO
    val mode = AudioTrack.MODE_STREAM
    val sessionId = AudioManager.AUDIO_SESSION_ID_GENERATE

    var audioTrack: AudioTrack? = null
    var codec: MediaCodec? = null
    var isPlaying = false
    var recordFileHelper = RecordFileHelper()
    var mediaFormat: MediaFormat? = null
    var minBufSize = 0

    init {
        var audioAttr = AudioAttributes.Builder()
            .setLegacyStreamType(streamType)
            .build()
        var format = AudioFormat.Builder()
            .setChannelMask(channelConfig)
            .setEncoding(audioFormat)
            .setSampleRate(sampleRateInHz)
            .build()
        minBufSize = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
        audioTrack = AudioTrack(audioAttr, format, minBufSize, mode, sessionId)
//        audioTrack = AudioTrack(
//            AudioManager.STREAM_MUSIC, sampleRateInHz,
//            channelConfig, audioFormat, minBufSize, AudioTrack.MODE_STREAM
//        )

        mediaFormat = MediaFormat.createAudioFormat(mime, sampleRate, channelCount)
        mediaFormat!!.setInteger(
            MediaFormat.KEY_BIT_RATE, sampleRate * 2 * channelCount
        )//码率
        mediaFormat!!.setInteger(MediaFormat.KEY_IS_ADTS, 1)
        mediaFormat!!.setInteger(
            MediaFormat.KEY_AAC_PROFILE,
            MediaCodecInfo.CodecProfileLevel.AACObjectLC
        )
        var data = ByteArray(2)
        data[0] = 0x14
        data[1] = 0x08.toByte()
        var csd0 = ByteBuffer.wrap(data)
        mediaFormat!!.setByteBuffer("csd-0", csd0)

        codec = MediaCodec.createDecoderByType(mime)

        codec!!.configure(mediaFormat, null, null, 0)
        println("---codec.configure()")
    }

    private fun startPlay() {
        println("---startPlay()")
        isPlaying = true
        audioTrack!!.play()
        codec!!.start()

        //循环从文件读取minBufSize的数据放入解码器解码
        var buf = ByteArray(minBufSize * 5)
        var fis = FileInputStream(recordFileHelper.getLastFile())
//        var fis =
//            FileInputStream(
//                Environment.getExternalStorageDirectory().absolutePath +
//                        "/ChatVoice/voice0"
//            )
        var offset = 0
        var len = fis.read(buf)

        while (isPlaying) {
            if (len <= 0) {
                Log.i(TAG, "startPlay: len=$len break while()")
                isPlaying = false
                break;
            }
            var firstSyncwordIdx = Adts.utils.findSyncWord(buf, offset, len)
            var secondSyncwordIdx =
                Adts.utils.findSyncWord(buf, firstSyncwordIdx + minAACFrameSize, len)

            Log.i(
                TAG, "1 firstIdx:$firstSyncwordIdx, secondIdx:$secondSyncwordIdx, " +
                        "framelen:${secondSyncwordIdx - firstSyncwordIdx} len:$len"
            )


            if (secondSyncwordIdx === -1) {
                Log.i(TAG, "read data")
                var tmpBuf = Arrays.copyOfRange(buf, firstSyncwordIdx, buf.size)
                System.arraycopy(tmpBuf, 0, buf, 0, tmpBuf.size)
                len = fis.read(buf, tmpBuf.size, buf.size - tmpBuf.size)
                offset = 0
                if(len <= 0)
                    isPlaying = false
                len+=tmpBuf.size//加上之前剩余的数据

//                var remainingLen = buf.size - firstSyncwordIdx
//                System.arraycopy(buf, firstSyncwordIdx, tmpBuf, 0, remainingLen)
//                System.arraycopy(tmpBuf, 0, buf, 0, remainingLen)
//                len = fis.read(buf, remainingLen, buf.size - remainingLen)
                Log.i(TAG, "startPlay: len=$len")
                continue
            }
            Log.i(
                TAG, "2 firstIdx:$firstSyncwordIdx, secondIdx:$secondSyncwordIdx, " +
                        "framelen:${secondSyncwordIdx - firstSyncwordIdx} len:$len"
            )

            offset = secondSyncwordIdx

            var aacFrame = ByteArray(secondSyncwordIdx - firstSyncwordIdx)
            System.arraycopy(buf, firstSyncwordIdx, aacFrame, 0, aacFrame.size)


            var index = codec!!.dequeueInputBuffer(1000)
            if (index >= 0) {
                var inputBuf = codec!!.getInputBuffer(index)
                inputBuf!!.clear()
                inputBuf.put(aacFrame, 0, aacFrame.size)
                codec!!.queueInputBuffer(index, 0, aacFrame.size, 0, 0)
            }

            var bufInfo = MediaCodec.BufferInfo()

            //循环从解码器获取解码后的pcm数据
            var outputBufIndex = codec!!.dequeueOutputBuffer(bufInfo, 1000)

            when (outputBufIndex) {
                MediaCodec.INFO_TRY_AGAIN_LATER -> Log.e(
                    TAG, "decode: 稍后再试"
                )
                MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> Log.e(
                    TAG, "decode: 输出格式改变"
                )
                else -> Log.e(TAG, "decode: " + outputBufIndex)

            }

            while (outputBufIndex >= 0 && isPlaying) {
                var outputBuf = codec!!.getOutputBuffer(outputBufIndex)

                var byteArray = ByteArray(bufInfo.size)
                outputBuf!!.get(byteArray)
                outputBuf.clear()
                audioTrack!!.write(byteArray, 0, bufInfo.size)

                codec!!.releaseOutputBuffer(outputBufIndex, false)
                outputBufIndex = codec!!.dequeueOutputBuffer(bufInfo, 3000)
            }
        }

        //release res
        fis.close()
        codec!!.stop()
        codec!!.release()
        audioTrack!!.stop()
        audioTrack!!.release()
    }

    override fun run() {
        startPlay()
    }

}